#include "n32g45x.h"
#include <module_usb.h>
#include <rtthread.h>

#include <usb_lib.h>
#include <usb_pwr.h>
#include <usb_type.h>
#include <usb_desc.h>

#include <thread_cfg.h>
#define LOG_TAG "module_usb"
#include <elog.h>

__IO uint8_t PrevXferComplete = 1;
__IO uint32_t TimingDelay     = 0;
u8 key_buffer[8]              = {0};
u8* Ep1DataPtr                = 0;
extern u8* EpOutDataPtrTmp;
extern u8* EpInDataPtrTmp;

// extern rt_event_t p_usb_event;
static struct rt_event usb_event;
rt_event_t p_usb_event = &usb_event;

extern rt_mq_t mqt_sync_keyboard_usb;
rt_uint8_t* keycode_src;

static rt_thread_t thread_usb;

ErrorStatus HSEStartUpStatus;

__IO uint16_t  calibration_value = 0;

static void thread_usb_entry(void* param)
{
    while(1)
    {
        if(PrevXferComplete)
        {
            PrevXferComplete = 0;

            if(rt_mq_recv(mqt_sync_keyboard_usb, key_buffer, sizeof(key_buffer), 10) == RT_EOK)
            {
                // rt_kprintf("USB Send Successful");
                Ep1DataPtr = key_buffer;
                USB_SilWrite(EP1_IN, Ep1DataPtr, 8);
                Ep1DataPtr = EpInDataPtrTmp;
            }
            else
            {
                key_buffer[0] = 0x00; //need update this
                key_buffer[1] = 0x00; //need update this
                key_buffer[2] = 0x00; //need update this
                key_buffer[3] = 0x00; //need update this
                key_buffer[4] = 0x00; //need update this
                key_buffer[5] = 0x00; //need update this
                key_buffer[6] = 0x00; //need update this
                key_buffer[7] = 0x00; //need update this
                
                Ep1DataPtr = key_buffer;
                USB_SilWrite(EP1_IN, Ep1DataPtr, 8);
                Ep1DataPtr = EpInDataPtrTmp;
                rt_thread_mdelay(10);
            }

            // key_buffer[2] = 0x06; //need update this
            // Ep1DataPtr = key_buffer;
            // USB_SilWrite(EP1_IN, Ep1DataPtr, 8);
            // Ep1DataPtr = EpInDataPtrTmp;
            // key_buffer[2] = 0;
        }

        rt_thread_mdelay(10);
    }
}

void thread_usb_init(void)
{
    USB_Set_System();
    USB_Interrupts_Config();
    Set_USBClock();
    USB_Init();

    while(bDeviceState != CONFIGURED);

    rt_err_t result;
    result = rt_event_init(&usb_event, "usb_event", RT_IPC_FLAG_PRIO);

    if(result != RT_EOK)
    {
        rt_kprintf("init event failed.\n");
        return;
    }

    thread_usb = rt_thread_create("tusb",
                                  thread_usb_entry,
                                  RT_NULL,
                                  THREAD_STACK_SIZE_LARGE,
                                  THREAD_PRIORITY_LV3,
                                  THREAD_TIMESLICE_SHORT);

    if(thread_usb != RT_NULL)
    {
        rt_thread_startup(thread_usb);
    }
}
INIT_APP_EXPORT(thread_usb_init);


/**
 * @brief Configures Main system clocks£¬Configures the different GPIO ports.
 */
void USB_Set_System(void)
{
    EXTI_InitType EXTI_InitStructure;
    /* Configure the EXTI line 18 connected internally to the USB IP */
    EXTI_ClrITPendBit(EXTI_LINE18);
    EXTI_InitStructure.EXTI_Line = EXTI_LINE18;
    EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitPeripheral(&EXTI_InitStructure);
}

/**
* @brief Configures USB Clock input (48MHz).
*/
void Set_USBClock(void)
{
    /* Select USBCLK source */
    RCC_ConfigUsbClk(RCC_USBCLK_SRC_PLLCLK_DIV3);
    /* Enable the USB clock */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_USB, ENABLE);
}

/**
 * @brief Power-off system clocks and power while entering suspend mode.
 */
void Enter_LowPowerMode(void)
{
    /* Set the device state to suspend */
    bDeviceState = SUSPENDED;
}

/**
 * @brief Restores system clocks and power while exiting suspend mode.
 */
void Leave_LowPowerMode(void)
{
    USB_DeviceMess* pInfo = &Device_Info;

    /* Set the device state to the correct state */
    if(pInfo->CurrentConfiguration != 0)
    {
        /* Device configured */
        bDeviceState = CONFIGURED;
    }
    else
    {
        bDeviceState = ATTACHED;
    }
}

/**
 * @brief Configures the USB interrupts.
 */
void USB_Interrupts_Config(void)
{
    NVIC_InitType NVIC_InitStructure;
    /* 2 bit for pre-emption priority, 2 bits for subpriority */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    /* Enable the USB interrupt */
    NVIC_InitStructure.NVIC_IRQChannel                   = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    /* Enable the USB Wake-up interrupt */
    NVIC_InitStructure.NVIC_IRQChannel                   = USBWakeUp_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

